﻿using System;
using System.Text;
using Up2Link.Core;

namespace Up2Link.SegString
{
    /// <summary>
    /// 类库提供的字符串分段消息类
    /// </summary>
    public class CMessageSS : IMessage
    {
        /// <summary>
        /// utf32编码
        /// </summary>
        public const Int32 ENCODING_UTF32 = 0;

        /// <summary>
        /// utf8编码
        /// </summary>
        public const Int32 ENCODING_UTF8 = 1;

        /// <summary>
        /// utf7编码
        /// </summary>
        public const Int32 ENCODING_UTF7 = 2;

        /// <summary>
        /// ascii编码
        /// </summary>
        public const Int32 ENCODING_ASCII = 3;

        /// <summary>
        /// unicode little endian编码(16位)
        /// </summary>
        public const Int32 ENCODING_UNICODE_LITTLE_ENDIAN = 4;

        /// <summary>
        /// unicode big endian编码(16位)
        /// </summary>
        public const Int32 ENCODING_UNICODE_BIG_ENDIAN = 5;

        /// <summary>
        /// 消息码
        /// </summary>
        private Int32 msgCode;

        /// <summary>
        /// 消息结束标志，为0时表示这条消息是一组消息的最后一个，非0时表示这条消息之后还有其他消息
        /// </summary>
        private Int32 finFlag;

        /// <summary>
        /// 消息附加内容的编码
        /// </summary>
        private Int32 encoding;

        /// <summary>
        /// 消息附加内容
        /// </summary>
        private String msgContent;

        /// <summary>
        /// 空的无参数构造函数
        /// </summary>
        public CMessageSS()
        {
        }

        /// <summary>
        /// 使用消息的各个部分作为参数的构造函数
        /// </summary>
        /// <param name="msgCode">消息码</param>
        /// <param name="finFlag">结束标记</param>
        /// <param name="encoding">附加内容的编码</param>
        /// <param name="msgContent">附加内容</param>
        public CMessageSS(Int32 msgCode, Int32 finFlag, Int32 encoding, String msgContent)
        {
            this.msgCode = msgCode;
            this.finFlag = finFlag;
            this.encoding = encoding;
            this.msgContent = msgContent;
        }

        /// <summary>
        /// 使用字节数组作为参数的构造函数
        /// </summary>
        /// <param name="msgBytes">消息的字节数组</param>
        public CMessageSS(Byte[] msgBytes)
        {
            Decode(msgBytes);
        }

        /// <summary>
        /// 将消息转化为简单的字符串
        /// </summary>
        /// <returns></returns>
        //public override String ToString()
        //{
        //    return "消息码：" + msgCode + (finFlag == 0 ? " 消息结束 " : " 消息未结束 ") + msgContent;
        //}

        /// <summary>
        /// 混合两条分段字符串消息
        /// </summary>
        /// <param name="msgSS">另一条消息</param>
        public void Merge(CMessageSS msgSS)
        {
            msgCode = msgSS.msgCode;
            finFlag = msgSS.finFlag;
            encoding = msgSS.encoding;
            msgContent = msgContent + "," + msgSS.msgContent;
        }

        #region 一组属性，用于获取消息的各部分信息

        /// <summary>
        /// 消息码
        /// </summary>
        public Int32 MsgCode
        {
            get { return msgCode; }
        }

        /// <summary>
        /// 结束标记
        /// </summary>
        public Int32 FinFlag
        {
            get { return finFlag; }
        }

        /// <summary>
        /// 编码
        /// </summary>
        public Int32 Enc
        {
            get { return encoding; }
        }

        /// <summary>
        /// 附加内容
        /// </summary>
        public String MsgContent
        {
            get { return msgContent; }
        }

        #endregion

        //实现IMessage接口必须的函数
        #region IMessage 成员

        /// <summary>
        /// 解码函数，将字节数组解码为消息
        /// SegString的具体结构为：
        /// 4字节的消息总长度
        /// 4字节的消息码
        /// 4字节的结束标志
        /// 4字节的编码信息
        /// 不定长度的消息内容
        /// </summary>
        /// <param name="msgBytes">消息的字节码</param>
        public void Decode(byte[] msgBytes)
        {
            msgCode = BitConverter.ToInt32(msgBytes, 4);
            finFlag = BitConverter.ToInt32(msgBytes, 8);
            encoding = BitConverter.ToInt32(msgBytes, 12);

            Encoding enc = Encoding.UTF32;
            switch (encoding)
            {
                case ENCODING_UTF32:
                    enc = Encoding.UTF32;
                    break;
                case ENCODING_UTF8:
                    enc = Encoding.UTF8;
                    break;
                case ENCODING_UTF7:
                    enc = Encoding.UTF7;
                    break;
                case ENCODING_ASCII:
                    enc = Encoding.ASCII;
                    break;
                case ENCODING_UNICODE_LITTLE_ENDIAN:
                    enc = Encoding.Unicode;
                    break;
                case ENCODING_UNICODE_BIG_ENDIAN:
                    enc = Encoding.BigEndianUnicode;
                    break;
            }
            msgContent = enc.GetString(msgBytes, 16, msgBytes.Length - 16);
        }

        /// <summary>
        /// 编码函数，将消息编码为字节数组
        /// SegString消息的具体格式参见Decode函数的注释
        /// </summary>
        /// <returns>编码后的消息字节码</returns>
        public byte[] Encode()
        {
            Byte[] codeBytes = BitConverter.GetBytes(msgCode);
            Byte[] flagBytes = BitConverter.GetBytes(finFlag);
            Byte[] encBytes = BitConverter.GetBytes(encoding);

            Encoding enc = Encoding.UTF32;
            switch (encoding)
            {
                case ENCODING_UTF32:
                    enc = Encoding.UTF32;
                    break;
                case ENCODING_UTF8:
                    enc = Encoding.UTF8;
                    break;
                case ENCODING_UTF7:
                    enc = Encoding.UTF7;
                    break;
                case ENCODING_ASCII:
                    enc = Encoding.ASCII;
                    break;
                case ENCODING_UNICODE_LITTLE_ENDIAN:
                    enc = Encoding.Unicode;
                    break;
                case ENCODING_UNICODE_BIG_ENDIAN:
                    enc = Encoding.BigEndianUnicode;
                    break;
            }
            Byte[] contentBytes = enc.GetBytes(msgContent);

            Int32 msgLength = 4 + codeBytes.Length + flagBytes.Length + encBytes.Length + contentBytes.Length;
            Byte[] msgBytes = new Byte[msgLength];
            BitConverter.GetBytes(msgLength).CopyTo(msgBytes, 0);

            codeBytes.CopyTo(msgBytes, 4);
            flagBytes.CopyTo(msgBytes, 8);
            encBytes.CopyTo(msgBytes, 12);
            contentBytes.CopyTo(msgBytes, 16);

            return msgBytes;
        }

        #endregion
    }
}
